--[[local --]]TargetsPreliminary, Targets = {}, {}
local Dummies = {
  "Training Bag",
  "Training Dummy",
  "Raider's Training Dummy",
}

local dummyttd = true
TTD = {}
local TTDM = {}

function AnimatedSetup()
  if not GStarRunning then
    GStarRunning = CreateFrame("Frame", "GStarRunning", UIParent)
    GStarRunning:SetFrameStrata("DIALOG")
    GStarRunning:SetWidth("64")
    GStarRunning:SetHeight("64")
    if GStarCactiX and GStarCactiY then
      GStarRunning:ClearAllPoints()
      GStarRunning:SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", GStarCactiX, GStarCactiY)
    else
      GStarRunning:ClearAllPoints()
      GStarRunning:SetPoint("CENTER")
    end
    GStarCacti = GStarRunning:CreateTexture("GStarCacti")
    GStarCacti:SetTexture("Interface\\Addons\\_ccR\\sys\\CactuarAnimated.tga")
    GStarCacti:SetAllPoints(GStarRunning)
    GStarRunning:SetMovable(true)
    GStarRunning:EnableMouse(true)
    GStarRunning:RegisterForDrag("LeftButton")
    GStarRunning:SetScript("OnDragStart", GStarRunning.StartMoving)
    GStarRunning:SetScript("OnDragStop", function(self) GStarCactiX, GStarCactiY = self:GetRect(); GStarRunning:StopMovingOrSizing() end)
    GStarMonitorRunning = CreateFrame("Frame", "GStarMonitorRunning", UIParent)
    GStarMonitorRunning:SetFrameStrata("DIALOG")
    GStarMonitorRunning:SetWidth("64")
    GStarMonitorRunning:SetHeight("64")
    GStarMonitorRunning:SetMovable(true)
    if GMonitorX and GMonitorY then
      GStarMonitorRunning:ClearAllPoints()
      GStarMonitorRunning:SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", GMonitorX, GMonitorY)
    else
      GStarMonitorRunning:ClearAllPoints()
      GStarMonitorRunning:SetPoint("CENTER")
    end

    GStarMonitor = GStarMonitorRunning:CreateTexture("GStarMonitor")
    GStarMonitor:SetTexture("Interface\\Addons\\_ccR\\sys\\GStarMonitor.tga")
    GStarMonitor:SetAllPoints(GStarMonitorRunning)

    GStarAoEOn = GStarMonitorRunning:CreateTexture("GStarAoEOn")
    GStarAoEOff = GStarMonitorRunning:CreateTexture("GStarAoEOff")
    GStarAoEOn:SetTexture("Interface\\Addons\\_ccR\\sys\\eyes.tga")
    GStarAoEOff:SetTexture("Interface\\Addons\\_ccR\\sys\\no.tga")

    GStarAoEOn:SetPoint("TOPLEFT", GStarMonitor, "TOPRIGHT", -29, -14)
    GStarAoEOn:SetSize(20, 20)
    GStarAoEOff:SetPoint("TOPLEFT", GStarMonitor, "TOPRIGHT", -29, -14)
    GStarAoEOff:SetSize(20, 20)

    GStarCDsOn = GStarMonitorRunning:CreateTexture("GStarCDsOn")
    GStarCDsOff = GStarMonitorRunning:CreateTexture("GStarCDsOff")
    GStarCDsOn:SetTexture("Interface\\Addons\\_ccR\\sys\\eyes.tga")
    GStarCDsOff:SetTexture("Interface\\Addons\\_ccR\\sys\\no.tga")

    GStarCDsOn:SetPoint("TOPLEFT", GStarMonitor, "RIGHT", -29, 0)
    GStarCDsOn:SetSize(20, 20)
    GStarCDsOff:SetPoint("TOPLEFT", GStarMonitor, "RIGHT", -29, 0)
    GStarCDsOff:SetSize(20, 20)

    GStarStunOn = GStarMonitorRunning:CreateTexture("GStarStunOn")
    GStarStunOff = GStarMonitorRunning:CreateTexture("GStarStunOff")
    GStarStunOn:SetTexture("Interface\\Addons\\_ccR\\sys\\eyes.tga")
    GStarStunOff:SetTexture("Interface\\Addons\\_ccR\\sys\\no.tga")

    GStarStunOn:SetPoint("TOPLEFT", GStarMonitor, "BOTTOMRIGHT", -29, 16)
    GStarStunOn:SetSize(20, 20)
    GStarStunOff:SetPoint("TOPLEFT", GStarMonitor, "BOTTOMRIGHT", -29, 16)
    GStarStunOff:SetSize(20, 20)

    GStarMonitorRunning:SetMovable()
    GStarMonitorRunning:EnableMouse(true)
    GStarMonitorRunning:RegisterForDrag("LeftButton")
    GStarMonitorRunning:SetScript("OnDragStart", GStarMonitorRunning.StartMoving)
    GStarMonitorRunning:SetScript("OnDragStop", function(self) GMonitorX, GMonitorY = self:GetRect(); GStarMonitorRunning:StopMovingOrSizing() end)
  end
end

  local cacti = {1, 2}
function AnimatedCacti(self, elapsed)
  
  if tContains(cacti, ccRS.UseAnkhyorG1zStar) or ccRS.UseAnkhyorG1zStar == nil then
    if not GStarRunning:IsVisible() then GStarRunning:Show() end -- do we need this?
    if GStarMonitorRunning:IsVisible() then GStarMonitorRunning:Hide() end -- do we need this?
    -- if ccR:IsVisible() then ccR:Hide() end
    if GStarMonitor:IsVisible() then
      GStarMonitor:Hide()
      GStarAoEOn:Hide()
      GStarCDsOn:Hide()
      GStarCDsOff:Hide()
      GStarStunOn:Hide()
      GStarAoEOff:Hide()
      GStarStunOff:Hide()
    end
    if not GStarCacti:IsVisible() then GStarCacti:Show() end
    AnimateTexCoords(GStarCacti, 128, 64, 64, 64, 2, elapsed, 0.1)
    return
  else
    if not GStarMonitorRunning:IsVisible() then GStarMonitorRunning:Show() end -- do we need this?
    if GStarRunning:IsVisible() then GStarRunning:Hide() end -- do we need this?
    if GStarCacti:IsVisible() then GStarCacti:Hide() end
    -- if ccR:IsVisible() then ccR:Hide() end
    if not GStarMonitor:IsVisible() then GStarMonitor:Show() end
    if (ccRS.Manual_AoE or ccRS.Auto_AoE) then
      if not GStarAoEOn:IsVisible() or GStarAoEOff:IsVisible() then
        GStarAoEOn:Show()
        GStarAoEOff:Hide()
      end
      AnimateTexCoords(GStarAoEOn, 512, 256, 64, 64, 29, elapsed, 0.1)
    elseif GStarAoEOn:IsVisible() or not GStarAoEOff:IsVisible() then
      GStarAoEOff:Show()
      GStarAoEOn:Hide()
    end    
    if useCDS then
      if not GStarCDsOn:IsVisible() or GStarCDsOff:IsVisible() then
        GStarCDsOn:Show()
        GStarCDsOff:Hide()
      end
      AnimateTexCoords(GStarCDsOn, 512, 256, 64, 64, 29, elapsed, 0.1)
    elseif GStarCDsOn:IsVisible() or not GStarCDsOff:IsVisible() then
      GStarCDsOn:Hide()
      GStarCDsOff:Show()
    end

    if isStun then
      if not GStarStunOn:IsVisible() or GStarStunOff:IsVisible() then
        GStarStunOn:Show()
        GStarStunOff:Hide()
      end
      AnimateTexCoords(GStarStunOn, 512, 256, 64, 64, 29, elapsed, 0.1)
    elseif GStarStunOn:IsVisible() or not GStarStunOff:IsVisible() then
      GStarStunOn:Hide()
      GStarStunOff:Show()
    end
  end
end

function AnimatedMaint(argument)
  if argument == "offeverything" then
    GStarRunning:SetScript("OnUpdate", nil)

    GStarMonitorRunning:Hide()
    GStarRunning:Hide()
    GStarMonitor:Hide()
    GStarStunOff:Hide()
    GStarAoEOff:Hide()
    GStarCDsOff:Hide()
    GStarStunOn:Hide()
    GStarAoEOn:Hide()
    GStarCDsOn:Hide()
    GStarCacti:Hide()
  end
  if argument == "oneverything" then
    GStarRunning:SetScript("OnUpdate", AnimatedCacti)

    GStarMonitorRunning:Show()
    GStarRunning:Show()
    GStarMonitor:Show()
    GStarStunOff:Show()
    GStarAoEOff:Show()
    GStarCDsOff:Show()
    GStarStunOn:Show()
    GStarAoEOn:Show()
    GStarCDsOn:Show()
    GStarCacti:Show()
  end
end

function usecooldownsg1zstar()
  if useCDS then
    useCDS = false
    print("cooldowns are off")
  else
    useCDS = true
    print("cooldowns are on")
  end
end

function round(num, idp)
   local mult = 10^(idp or 0)
   return math.floor(num * mult + 0.5) / mult
end

function GroupComposer()
    
    if not GroupComposerFrameCheck then GroupComposerFrame() end
    local groupplayernumber = GetNumGroupMembers()
    local roletable = {tanks = {}, healers = {}, dps = {}, none = {}}
    
    if GetRaidDifficultyID() == 3 or GetRaidDifficultyID() == 5 then -- 10
      for i = 1, groupplayernumber do

        local name = GetRaidRosterInfo(i)

        if UnitGroupRolesAssigned("raid"..i) == "TANK" then
          table.insert(roletable.tanks, {name, "raid"..i})
        elseif UnitGroupRolesAssigned("raid"..i) == "HEALER" then
          table.insert(roletable.healers, {name, "raid"..i})
        elseif UnitGroupRolesAssigned("raid"..i) == "DAMAGER" then
          table.insert(roletable.dps, {name, "raid"..i})
        elseif UnitGroupRolesAssigned("raid"..i) == "NONE" then
          InitiateRolePoll()
          table.insert(roletable.none, {name, "raid"..i})
        end
      end

      local confirmedroles = #roletable.tanks + #roletable.healers + #roletable.dps

      if confirmedroles == 10 then return
      elseif confirmedroles + #roletable.none == 10 then InitiateRolePoll() return
      elseif confirmedroles + #roletable.none < 10 then
        
        local missingpeople = 10 - confirmedroles
        local missingtanks, missinghealers, missingdps

        if #roletable.tanks ~= 2 then
          missingtanks = ""..2-#roletable.tanks.." tank(s) "
        else missingtanks = "" end
        
        if #roletable.healers ~= 2 then
          missinghealers = ""..2-#roletable.healers.." healers(s) "
        else missinghealers = "" end

        if #roletable.dps ~= 6 then
          missingdps = ""..6-#roletable.dps.." dps "
        else missingdps = "" end

        GroupComposerFrame("LF"..missingpeople.."M "..missingtanks..missinghealers..missingdps.."550+ 10NM SoO at .")
      end
    end
    
    if GetRaidDifficultyID() == 4 or GetRaidDifficultyID() == 6 then -- 25
      for i = 1, groupplayernumber do

        local name = GetRaidRosterInfo(groupplayernumber)

        if UnitGroupRolesAssigned("raid"..i) == "TANK" then
          table.insert(roletable.tanks, {name, "raid"..i})
        elseif UnitGroupRolesAssigned("raid"..i) == "HEALER" then
          table.insert(roletable.healers, {name, "raid"..i})
        elseif UnitGroupRolesAssigned("raid"..i) == "DAMAGER" then
          table.insert(roletable.dps, {name, "raid"..i})
        elseif UnitGroupRolesAssigned("raid"..i) == "NONE" then
          InitiateRolePoll()
          table.insert(roletable.none, {name, "raid"..i})
        end
      end

      local confirmedroles = #roletable.tanks + #roletable.healers + #roletable.dps

      if confirmedroles == 25 then return
      elseif confirmedroles + #roletable.none == 25 then InitiateRolePoll() return
      elseif confirmedroles + #roletable.none < 25 then

        local missingpeople = 25 - confirmedroles
        local missingtanks, missinghealers, missingdps
        
        if #roletable.tanks ~= 2 then
          missingtanks = ""..2-#roletable.tanks.." tank(s) "
        else missingtanks = "" end

        if #roletable.healers ~= 5 then
          missinghealers = ""..5-#roletable.healers.." healers(s) "
        else missinghealers = "" end

        if #roletable.dps ~= 18 then
          missingdps = ""..18-#roletable.dps.." dps "
        else missingdps = "" end

        GroupComposerFrame("LF"..missingpeople.."M "..missingtanks..missinghealers..missingdps.."550+ 25NM SoO at .")
      end
    end
end

function GroupComposerFrame(turn, yesno, failed)
  if failed then
    groupcomposereditbox:Hide()
    buttonyes:Hide()
    buttonno:Hide()
    button:Hide()
    groupcomposereditbox:SetFocus()
    groupcomposereditbox:SetText("ccR: Failed to get revision number make sure you have 'Revision.txt' in the ccR folder.")
    groupcomposereditbox:SetScript("OnTextChanged", function() groupcomposereditbox:SetText("ccR: Failed to get revision number make sure you have 'Revision.txt' in the ccR folder.") end)
    groupcomposereditbox:HighlightText()
    groupcomposereditbox:Show()
    -- buttonyes:Show()
    -- buttonno:Show()
    button:Show()
    return
  end
  if yesno then
    groupcomposereditbox:Hide()
    buttonyes:Hide()
    buttonno:Hide()
    button:Hide()
    groupcomposereditbox:SetFocus()
    groupcomposereditbox:SetText("ccR: There's an update. Open changelog?")
    groupcomposereditbox:SetScript("OnTextChanged", function() groupcomposereditbox:SetText("ccR: There's an update. Open changelog?") end)
    groupcomposereditbox:HighlightText()
    groupcomposereditbox:Show()
    buttonyes:Show()
    buttonno:Show()
    return
  end
  if turn then
    groupcomposereditbox:Hide()
    buttonyes:Hide()
    buttonno:Hide()
    button:Hide()
    groupcomposereditbox:SetFocus()
    groupcomposereditbox:SetText(turn)
    groupcomposereditbox:SetScript("OnTextChanged", function() groupcomposereditbox:SetText(""..turn.."") end)
    groupcomposereditbox:HighlightText()
    groupcomposereditbox:Show()
    button:Show()
    return
  end
  GroupComposerFrameCheck = true
  groupcomposereditbox = CreateFrame("EditBox", nil, UIParent)
  groupcomposereditboxLeft = groupcomposereditbox:CreateTexture(nil, "BACKGROUND")
  groupcomposereditboxRight = groupcomposereditbox:CreateTexture(nil, "BACKGROUND")
  groupcomposereditboxMiddle = groupcomposereditbox:CreateTexture(nil, "BACKGROUND")
  do
    groupcomposereditboxLeft:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
    groupcomposereditboxLeft:SetHeight(32)
    groupcomposereditboxLeft:SetWidth(64)
    groupcomposereditboxLeft:SetPoint("LEFT", -14, 0)
    groupcomposereditboxLeft:SetTexCoord(0, 0.125, 0, 1)
    groupcomposereditboxRight:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
    groupcomposereditboxRight:SetHeight(32)
    groupcomposereditboxRight:SetWidth(64)
    groupcomposereditboxRight:SetPoint("RIGHT", 6, 0)
    groupcomposereditboxRight:SetTexCoord(0.875, 1, 0, 1)
    groupcomposereditboxMiddle:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
    groupcomposereditboxMiddle:SetHeight(32)
    groupcomposereditboxMiddle:SetWidth(1)
    groupcomposereditboxMiddle:SetPoint("LEFT", groupcomposereditboxLeft, "RIGHT")
    groupcomposereditboxMiddle:SetPoint("RIGHT", groupcomposereditboxRight, "LEFT")
    groupcomposereditboxMiddle:SetTexCoord(0, 0.9375, 0, 1)
  end
  groupcomposereditbox:SetHeight(32)
  groupcomposereditbox:SetWidth(250)
  groupcomposereditbox:SetPoint("TOP", 0, -16)
  groupcomposereditbox:SetFontObject("GameFontHighlight")
  groupcomposereditbox:SetTextInsets(0, 0, 0, 1)
  groupcomposereditbox:SetFocus()
  groupcomposereditbox:HighlightText()

  buttonyes = CreateFrame("Button", nil, groupcomposereditbox)
  buttonyes:SetHeight(24)
  buttonyes:SetWidth(75)
  buttonyes:SetPoint("BOTTOMLEFT", 0, -20)
  buttonyes:SetNormalFontObject("GameFontNormal")
  buttonyes:SetHighlightFontObject("GameFontHighlight")
  buttonyes:SetNormalTexture(buttonyes:CreateTexture(nil, nil, "UIPanelButtonUpTexture"))
  buttonyes:SetPushedTexture(buttonyes:CreateTexture(nil, nil, "UIPanelButtonDownTexture"))
  buttonyes:SetHighlightTexture(buttonyes:CreateTexture(nil, nil, "UIPanelButtonHighlightTexture"))
  buttonyes:SetText(YES)

  buttonno = CreateFrame("Button", nil, groupcomposereditbox)
  buttonno:SetHeight(24)
  buttonno:SetWidth(75)
  buttonno:SetPoint("BOTTOMRIGHT", 0, -20)
  buttonno:SetNormalFontObject("GameFontNormal")
  buttonno:SetHighlightFontObject("GameFontHighlight")
  buttonno:SetNormalTexture(buttonno:CreateTexture(nil, nil, "UIPanelButtonUpTexture"))
  buttonno:SetPushedTexture(buttonno:CreateTexture(nil, nil, "UIPanelButtonDownTexture"))
  buttonno:SetHighlightTexture(buttonno:CreateTexture(nil, nil, "UIPanelButtonHighlightTexture"))
  buttonno:SetText(NO)

  buttonyes:SetScript("OnClick", function(self)
    groupcomposereditbox:Hide()
    OpenURL("https://code.google.com/p/fh-ccr/wiki/Changelog")
    buttonyes:Hide()
    buttonno:Hide()
    end)
  buttonno:SetScript("OnClick", function(self)
    groupcomposereditbox:Hide()
    buttonyes:Hide()
    buttonno:Hide()
  end)

  button = CreateFrame("Button", nil, groupcomposereditbox)
  button:SetHeight(24)
  button:SetWidth(75)
  button:SetPoint("BOTTOM", 0, -20)
  button:SetNormalFontObject("GameFontNormal")
  button:SetHighlightFontObject("GameFontHighlight")
  button:SetNormalTexture(button:CreateTexture(nil, nil, "UIPanelButtonUpTexture"))
  button:SetPushedTexture(button:CreateTexture(nil, nil, "UIPanelButtonDownTexture"))
  button:SetHighlightTexture(button:CreateTexture(nil, nil, "UIPanelButtonHighlightTexture"))
  button:SetText(OKAY)
  button:Show()
  button:SetScript("OnClick", function(self)
         groupcomposereditbox:Hide()
         button:Hide()
  end)
  groupcomposereditbox:Hide()
  buttonyes:Hide()
  buttonno:Hide()
  button:Hide()
end

function _ThrottleFrame()

  unitclass = select(3, UnitClass("player"))

  if not debuffframe then
    debuffframe = CreateFrame("GameTooltip", "debuffframe", UIParent, "GameTooltipTemplate")
    debuffframe:SetOwner(UIParent, "ANCHOR_NONE")
  end

  if not spellframe then
    spellframe = CreateFrame("GameTooltip", "spellframe", UIParent, "GameTooltipTemplate")
    spellframe:SetOwner(UIParent, "ANCHOR_NONE")
  end

  if unitclass == 8 and not tRuneOfPower then -- mage
    tRuneOfPower = 0
    _RuneToggle = 0
  end

  if not ThrottleFrame then
    ThrottleFrame = CreateFrame("Frame", "ThrottleFrame", UIParent)
    -- ThrottleFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
    ThrottleFrame:SetScript("OnEvent", ThrottleFrameFunction)
  end

  if not GTargetListFrame then
    GTargetListFrame = CreateFrame("Frame", "GTargetListFrame", UIParent)
    GTargetListFrame:SetScript("OnUpdate", GTargetListControl)
  end
end

function ThrottleFrameFunction(self, registeredevent, ...)

  if registeredevent == "PLAYER_DEAD" then
    -- _ImmolateThrottle = 0
    _ImpendingVictory = false
    _PiercingHowl = false
    _Shockwave = false
    _StormBolt = false
    _Disarm = false
    _IntimidatingShout = false
    _ShatteringThrow = false
    _VictoryRush = false
    _BlindingLight = false
    _DivineShield = false
    _Stun = false
    _Mend = false
  end

  local timestamp, event, hidecaster, sourceguid, sourcename, sourceflags, sourceraidflags, destguid, destname, destflags, destraidflags, spellid, spellname = ...

  if spellid == 114207 and event == "SPELL_CAST_SUCCESS" then -- skull banner track
    tSkullBanner = GetTime()+10
    return
  end

  if sourcename ~= UnitName("player") and sourcename ~= "Thok the Bloodthirsty" then return end -- no need to run

  if event == "SPELL_CAST_START" then

    if sourcename == "Thok the Bloodthirsty" and spellname == "Deafening Screech" then
      ThokThrottle = select(6, UnitCastingInfo("boss1"))
      return
    end
    
    if spellid == 348 then -- warlock immolate throttle
      _ImmolateThrottle = 1
      return
    end
    
    return
  end

  if event == "SPELL_CAST_FAILED" then
    
    -- warrior
    if spellid == 6673 or spellid == 469 then -- last shout
      _Shout = spellid
      return
    end
    if spellid == 103840 and not _ImpendingVictory then -- impending victory
      _ImpendingVictory = true
      return
    end
    if spellid == 12323 and not _PiercingHowl then -- piercing howl
      _PiercingHowl = true
      return
    end
    if spellid == 46968 and not _Shockwave then -- shockwave
      _Shockwave = true
      return
    end
    if spellid == 107570 and not _StormBolt then -- stormbolt
      _StormBolt = true
      return
    end
    if spellid == 676 and not _Disarm then -- disarm
      _Disarm = true
      return
    end
    if spellid == 5246 and not _IntimidatingShout then -- intimidating shout
      _IntimidatingShout = true
      return
    end
    if spellid == 64382 and not _ShatteringThrow then -- shattering throw
      _ShatteringThrow = true
      return
    end
    if spellid == 34428 and not _VictoryRush then -- victory rush
      _VictoryRush = true
      return
    end
    -- warrior

    -- paladin
      if spellid == 115750 then -- blinding light
        _BlindingLight = true
        return
      end
      if spellid == 642 then -- divine shield
        _DivineShield = true
        return
      end
      if spellid == 105593 or spellid == 853 then -- paladin stun
        _Stun = true
        return
      end
    -- paladin

    -- Hunter
      if spellid == 136 then -- mend pet
      _Mend = true
      return
    end
    -- Hunter

    if spellid == 348 then -- warlock un throttle immolate
      _ImmolateThrottle = 0
      return
    end

    return
  end

  if event == "SPELL_CAST_SUCCESS" then

    -- warrior
    if spellid == 6673 or spellid == 469 then -- last shout
      _Shout = spellid
      return
    end
    if spellid == 103840 and _ImpendingVictory then -- impending victory
      _ImpendingVictory = false
      return
    end
    if spellid == 12323 and _PiercingHowl then -- piercing howl
      _PiercingHowl = false
      return
    end
    if spellid == 46968 and _Shockwave then -- shockwave
      _Shockwave = false
      return
    end
    if spellid == 107570 and _StormBolt then -- stormbolt
      _StormBolt = false
      return
    end
    if spellid == 676 and  _Disarm then -- disarm
      _Disarm = false
      return
    end
    if spellid == 5246 and  _IntimidatingShout then -- intimidating shout
      _IntimidatingShout = false
      return
    end
    if spellid == 64382 and  _ShatteringThrow then -- shattering throw
      _ShatteringThrow = false
      return
    end
    if spellid == 34428 and _VictoryRush then -- victory rush
      _VictoryRush = false
      return
    end
    -- warrior

    -- paladin
      if spellid == 115750 then -- blinding light
        _BlindingLight = false
        return
      end
      if spellid == 642 then -- divine shield
        _DivineShield = false
      return
    end
      if spellid == 105593 or spellid == 853 then -- paladin stun
        _Stun = false
        return
      end
    -- paladin

    -- hunter
      if spellid == 136 then -- mend pet
        _Mend = false
        return
      end
    -- hunter

    if spellid == 50842 then -- dk 28 sec cooldown pestilence
      tLastUsedPestilence = GetTime()
      return
    end

    if spellid == 781 and HDDisengage then -- hunter disengage
      HD2()
      return
    end

    if spellid == 116011 then -- mage rune of power
      _RuneToggle = GetTime()+0.5
      tRuneOfPower = GetTime()
      return
    end

    if spellid == 348 then -- warlock immolate unthrottle general throttle mob
      _ImmolateThrottle = 0
      _G[destguid.." ImmolateThrottle"] = 2
      _G[destguid.." ImmolateOldCrit"] = GetSpellCritChance(3)
      return
    end

    return
  end

  if event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH" then

    if spellid == 118253 then -- survival hunter serpent sting
      _G[destguid.."_tSerpentSting"] = GetTime()
      return
    end

    if spellid == 348 then -- warlock unthrottle immolate specific mob
      _G[destguid.." ImmolateThrottle"] = 0
      return
    end

    if spellid == 146046 then _PBI = GetTime() return end -- mage alter time PBI
    
    return
  end
end

function InterruptTrainer()

  local unitclass = select(3, UnitClass("player"))

  if unitclass == 1 then -- warrior

    -- if ccrPlayerHasTalent(102060) then interruptid = {102060, 6552}
    -- else
      interruptid = 6552
    -- end

  elseif unitclass == 2 then -- paladin

    interruptid = 96231 -- Rebuke

  elseif unitclass == 3 then -- hunter

    if GetSpecialization() == 2 then interruptid = 34490 -- marksmanship
    else
      interruptid = 147362
    end

  elseif unitclass == 11 then -- druid

    if GetSpecialization() == 1 then interruptid = 78675
    elseif GetSpecialization() == 2 then interruptid = 106839
    elseif GetSpecialization() == 3 then interruptid = 106839
    elseif GetSpecialization() == 4 then return
    end

  elseif unitclass == 10 then interruptid = 116075 -- monk

  elseif unitclass == 6 then interruptid = --[[{--]]47528--[[, 47476}--]]

  elseif unitclass == 8 then interruptid = 2139

  elseif unitclass == 5 then

    if GetSpecialization() == 3 then interruptid = 15487
    else
      return
    end

  elseif unitclass == 4 then interruptid = 1766 -- rogue

  elseif unitclass == 7 then interruptid = 57994

  elseif unitclass == 9 then

    if ccrPlayerHasTalent(--[["Grimoire of Supremacy"--]]108499) then interruptid = 115781
    else
      interruptid = 19647
    end
  end

  local spellcasting = UnitCastingInfo("target")
  local spelltable = {"Arcane Shock", --[["Ancestral Chain Heal",--]] "Chain Heal", "Corruption Shock", "Earthen Shard", "Empowered Chain Heal", "Forbidden Magic", "Hurl Corruption", "Magistrike", "Mind Spike", "Mocking Blast",}
  -- local spelltableWoD = {--[["Arcane Burst",--]] "Briarskin", "Cauterize Wounds", "Cauterizing Bolt", "Chaos Bolt", "Decay", "Dibilitating Fixation", "Drain Life", "Fel Blast", "Ferocious Yell", --[["Fireball", "Frostbolt",]]"Molten Blast", --[["Parasitic Growth",--]]"Rapid Tides"}

  if tContains(spelltable, spellcasting) then
      ccrCast(interruptid)
    return
  end

  -- for k, v in pairs(spelltable) do
  --   if spellcasting == v then
  --     ccrCast(interruptid)
  --     break
  --   end
  -- end

  -- if UnitCastingInfo("target") == "Mind Spike" or UnitCastingInfo("target") == "Mocking Blast" or UnitCastingInfo("target") == "Empowered Chain Heal" or UnitCastingInfo("target") == "Corruption Shock" or UnitCastingInfo("target") == "Hurl Corruption" or UnitCastingInfo("target") == "Chain Heal" or UnitCastingInfo("target") == "Arcane Shock" or UnitCastingInfo("target") == "Magistrike" then
  --   ccrCast(interruptid)
  -- end
end

function TauntTrainer()

  -- no need to run
  if not Focus or not Target then
    return
  elseif UnitThreatSituation("player", "target") == nil or UnitThreatSituation("player", "target") > 1 then
    return
  end
  -- no need to run

  -- local othertank = UnitName("focus")
  local unitclass = select(3, UnitClass("player"))

  if unitclass == 1 then -- warrior
    tauntid = 355
  elseif unitclass == 2 then -- paladin
    tauntid = 62124
  elseif unitclass == 11 then -- druid
    tauntid = 6795
  elseif unitclass == 10 then -- monk
    tauntid = 115546
  elseif unitclass == 6 then -- deathknight
    tauntid = {56222, 49576}
  end

  if UnitName("target") == "Immerseus" and UnitDebuff("focus", "Corrosive Blast") and not UnitDebuff("player", "Corrosive Blast") then
    ccrCast(tauntid)
  elseif UnitName("target") == "Sha of Pride" and UnitDebuff("focus", "Wounded Pride") and not UnitDebuff("player", "Wounded Pride") then
    ccrCast(tauntid)
  elseif UnitName("target") == "Galakras" and UnitDebuff("focus", "Flames of Galakrond") and tonumber(select(4, UnitDebuff("focus", "Flames of Galakrond"))) > 2 and not UnitDebuff("player", "Flames of Galakrond") then
    ccrCast(tauntid)
  elseif UnitName("target") == "Iron Juggernaut" and UnitDebuff("focus", "Ignite Armor") and tonumber(select(4, UnitDebuff("focus", "Ignite Armor"))) > 2 and not UnitDebuff("player", "Ignite Armor") then
    ccrCast(tauntid)
  -- elseif UnitThreatSituation("player", "target") < 2 and UnitName("target") == "Earthbreaker Haromm" and select(4, UnitAura("focus", "Froststorm Strike")) > 4 and not UnitAura("player", "Froststorm Strike") then
  --   ccrCast(tauntid)
  --   
  elseif UnitName("target") == "General Nazgrim" and UnitDebuff("focus", "Sundering Blow") and tonumber(select(4, UnitDebuff("focus", "Sundering Blow") > 2)) and not UnitDebuff("player", "Sundering Blow") then
    ccrCast(tauntid)
  -- elseif UnitThreatSituation("player", "target") < 2 and UnitName("target") == "Malkorok" and select(4, UnitAura("focus", "Fatal Strike")) > 14 and not UnitAura("player", "Fatal Strike") then
  -- ccrCast(tauntid)
  --   
  -- elseif UnitName("target") == "Thok the Bloodthirsty" and select(4, UnitAura("focus", "Panic")) > 2 and not UnitAura("player", "Panic") then
  --   ccrCast(tauntid)
  --   
  -- elseif UnitName("target") == "Thok the Bloodthirsty" and select(4, UnitAura("focus", "Acid Breath")) > 2 and not UnitAura("player", "Acid Breath") then
  --   ccrCast(tauntid)
  --   
  -- elseif UnitName("target") == "Thok the Bloodthirsty" and select(4, UnitAura("focus", "Scorching Breath")) > 2 and not UnitAura("player", "Scorching Breath") then
  --   ccrCast(tauntid)
  --   
  elseif UnitName("target") == "Siegecrafter Blackfuse" and UnitDebuff("focus", "Electrostatic Charge") and tonumber(select(4, UnitDebuff("focus", "Electrostatic Charge"))) > 2 and not UnitDebuff("player", "Electrostatic Charge") then
    ccrCast(tauntid)
  elseif UnitName("target") == "Garrosh Hellscream" and UnitDebuff("focus", "Gripping Despair") and tonumber(select(4, UnitDebuff("focus", "Gripping Despair"))) > 2 and not UnitDebuff("player", "Gripping Despair") then
    ccrCast(tauntid)
  elseif UnitName("target") == "Garrosh Hellscream" and UnitDebuff("focus", "Empowered Gripping Despair") and tonumber(select(4, UnitDebuff("focus", "Empowered Gripping Despair"))) > 2 and not UnitDebuff("player", "Empowered Gripping Despair") then
    ccrCast(tauntid)
  end
end

function HunterDisengage()

 _ThrottleFrame()
 
 degrees = select(4, Player:GetLocation())
 degreesr = round(degrees, 6)
 
 if degrees+math.pi > 1.99999831016228*math.pi then
    degreestwo = degrees-math.pi
    degreestwor = round(degreestwo, 6)
    FaceDirection(degreestwo)
 else
    degreestwo = degrees+math.pi
    degreestwor = round(degreestwo, 6)     
    FaceDirection(degreestwo)
 end
 
 HDDisengage = true
 SetTimerCallback(HD1, 1)
end

function HD1()
   if round(select(4, Player:GetLocation()), 6) == degreestwor then
      CastSpellByID(781)
   end
end

function HD2()
  RemoveTimerCallback(HD1)
  FaceDirection(degrees)
  HDDisengage = false
  -- SetTimerCallback(HD3, 1)
  -- ToggleAutoRun()
end

function HD3()
  if round(select(4, Player:GetLocation()), 6) == degreesr then
    ToggleAutoRun()
    RemoveTimerCallback(HD3)
  end
end

function TicksRemaining(guid, spell, tickoption)

  if type(spell) == "number" then spell = SpellIDToName(spell) end

  --
    -- if spell == 980 then
    --   spell = "Agony"
    -- elseif spell == 172 then
    --   spell = "Corruption"
    -- elseif spell == 48181 then
    --   spell = "Haunt"
    -- elseif spell == 27243 then
    --   spell = "Seed of Corruption"
    -- elseif spell == 30108 then
    --   spell = "Unstable Affliction"
    -- elseif spell == 103103 then
    --   spell = "Malefic Grasp"
    -- elseif spell == 1120 then
    --   spell = "Drain Soul"
    -- elseif spell == 348 then
    --   spell = "Immolate"
    -- elseif spell == 8050 then
    --   spell = "Flame Shock"
    -- end
  --
  if tonumber(guid) then  
    if not IExists(guid) then return end
    ISetAsUnitID(guid, "Internal")
    local name, _, _, _, _, duration, expires = UnitDebuff("target", ""..spell.."", "", "PLAYER")

    if tickoption and name then
      debuffframe:ClearLines()
      debuffframe:SetUnitDebuff("Internal", IndexFinder(spell), "PLAYER")
      if not debuffframeTextLeft2:GetText() then return nil end
      local tickevery = tonumber(string.match(debuffframeTextLeft2:GetText(), '%d+%.%d+'))
      return tickevery
    elseif name then
      debuffframe:ClearLines()
      debuffframe:SetUnitDebuff("Internal", IndexFinder(spell), "PLAYER")
      if debuffframeTextLeft2:GetText() == nil then return 0 end
      local tickevery = tonumber(string.match(debuffframeTextLeft2:GetText(), '%d+%.%d+'))
      return ceil((expires-GetTime())/tickevery)
    else
      return 0
    end
  else
  local name, _, _, _, _, duration, expires = UnitDebuff("target", ""..spell.."", "", "PLAYER")

    if tickoption and name then
      debuffframe:ClearLines()
      debuffframe:SetUnitDebuff("target", IndexFinder(spell), "PLAYER")
      if not debuffframeTextLeft2:GetText() then return nil end
      local tickevery = tonumber(string.match(debuffframeTextLeft2:GetText(), '%d+%.%d+'))
      return tickevery
    elseif name then
      debuffframe:ClearLines()
      debuffframe:SetUnitDebuff("target", IndexFinder(spell), "PLAYER")
      if debuffframeTextLeft2:GetText() == nil then return 0 end
      local tickevery = tonumber(string.match(debuffframeTextLeft2:GetText(), '%d+%.%d+'))
    return ceil((expires-GetTime())/tickevery)
  else
    return 0
  end
end
end

function IndexFinder(spell, buff, target) -- add buff or debuff and target\player support
  for i = 1, 40 do
    local name = UnitDebuff("target", i, "PLAYER")
    if name and name == spell then
      return i
    elseif not name then
      break
    end
  end 
end

function PandemicNewTotalTicks(spell)
  if spell == 980 then spell = "Agony"
  elseif spell == 172 then spell = "Corruption"
  elseif spell == 48181 then spell = "Haunt"
  elseif spell == 27243 then spell = "Seed of Corruption"
  elseif spell == 30108 then spell = "Unstable Affliction"
  elseif spell == 103103 then spell = "Malefic Grasp"
  elseif spell == 1120 then spell = "Drain Soul"    
  end
  local name, _, _, _, _, duration, expires = UnitDebuff("target", ""..spell.."", "", "PLAYER")
  if name then
    if expires-GetTime() >= tAfflictionBaseDuration.spell*1.5 then tNewDuration = tAfflictionBaseDuration.spell*1.5
    else tNewDuration = expires-GetTime()+tAfflictionBaseDuration.spell
    end
    return tNewDuration/(2/(1+UnitSpellHaste("player")/100))
  else
    return tAfflictionBaseDuration.spell/(2/(1+UnitSpellHaste("player")/100))
  end
end

-- NOT ACTUALLY MY SHIT FORGOT WHO THIS WAS
-- DEATHKNIGHT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--[[ blood, frost, unholy, death = GetRunes()
  @return
    blood - Number of ready blood runes. [0-2] (number)
    frost - Number of ready frost runes. [0-2] (number)
    unholy - Number of ready unholy runes. [0-2] (number)
    death   - Number of ready death runes. [0-2] (number) ]]
function GetRunesG1zStar()
  
  local blood, frost, unholy, death = 0,0,0,0
  local type
  for i=1,6 do
    type    =  GetRuneType(i)
    if  select(3, GetRuneCooldown(i)) then -- ready
      if type == 1 then
        blood = blood + 1
      elseif type == 2 then
        unholy = unholy + 1
      elseif type == 3 then
        frost = frost + 1
      elseif type == 4 then
        death = death + 1
      end
    end
  end
  return blood, frost, unholy, death
end
--[[ depleted = GetDepletedRunes()
        @return depleted        - number of fully delpleted runes [0-3] (number) ]]
function GetDepletedRunesG1zStar()
  
  local regenThreshold  = 1
  local depleted = 0
  for i=1,6,2 do
    local start, duration, runeReady = GetRuneCooldown(i)
    local start2, duration2, runeReady2 = GetRuneCooldown(i+1)
    if not runeReady and not runeReady2 and duration > 0 and duration2 > 0 and start > 0 and start2 > 0 then
      if (start-GetTime()+duration)>=regenThreshold and (start2-GetTime()+duration2)>=regenThreshold then
        depleted = depleted + 1
      end
    end
  end
  return depleted
end

function Dec2Hex(nValue)
   if type(nValue) == "string" then
    nValue = tonumber(nValue);
   end
   nHexVal = string.format("%X", nValue);  -- %X return uppercase hex, %x gives lowercase letters
   sHexVal = nHexVal.."";
   return sHexVal;
end
-- NOT ACTUALLY MY SHIT FORGOT WHO THIS WAS

  local revision = tonumber(ReadFile("\\World of Warcraft\\Interface\\AddOns\\_ccR\\Revision.txt"))
function ccR_Update(text)

  -- ccR:Hide()
  AnimatedMaint("offeverything")
  ccrStart = false

  if not revision then GroupComposerFrame("turn", 1, 1) return end

  -- local wRevision = string.match(text, "r%d%d%d")
  -- local wRevisionU = string.gsub(wRevision, "r", "")
  local wRevisionU = string.gsub(string.match(text, "r%d%d%d"), "r", "")
  
  if tonumber(wRevisionU) > revision then
    GroupComposerFrame("turn", 1)
  end
end

function G1zStarSlowfallfunc()
  if IsFalling() and GetDistanceFallen() > 11 and not UnitIsDeadOrGhost("player") then
    StopFalling();
    playerX, playerY, playerZ = Player:GetLocation();
    MoveTo(playerX, playerY+0.00000001, playerZ);
  end  
end

function G1zStarTimelessIsleBuffsUpTime()
  if GetCurrentMapContinent() == 6 and GetCurrentMapZone() == 10 then
    if not UnitBuff("player","Singing Crystal") and GetItemCount(103641,false,false) > 0 then UseItemByName(103641) end
    if not UnitBuff("player","Book of the Ages") and GetItemCount(103642,false,false) > 0 then UseItemByName(103642) end
    if not UnitBuff("player","Dew of Eternal Morning") and GetItemCount(103643,false,false) > 0 then UseItemByName(103643) end
    if not UnitBuff("player","Visions of Insanity") and GetItemCount(86569,false,false) > 0 and GetItemCooldown(86569) == 0 then UseItemByName(86569) end
    if not UnitBuff("player","Symbiotic Growth") and GetItemCount(86580,false,false) > 0 and GetItemCooldown(86580) == 0 then UseItemByName(86580) end
  end 
end

-- Tables for Tier Bonus and Trinkets
local gTierCheck = {}

    gTierCheck.Warrior = {}
    gTierCheck.Warrior.S1 = {}
    gTierCheck.Warrior.S2 = {}
    gTierCheck.Warrior.S3 = {}
    gTierCheck.Warrior.S1.t15 = {95990, 95989, 95988, 95987, 95986, 95330, 95331, 95332, 95333, 95334, 96734, 96733, 96732, 96731, 96730}
    gTierCheck.Warrior.S2.t15 = {95990, 95989, 95988, 95987, 95986, 95330, 95331, 95332, 95333, 95334, 96734, 96733, 96732, 96731, 96730}
    gTierCheck.Warrior.S3.t15 = {95991, 95992, 95993, 95994, 95995, 95335, 95336, 95337, 95338, 95339, 96735, 96736, 96737, 96738, 96739}
    gTierCheck.Warrior.S1.t16 = {99047, 99046, 99036, 99035, 99034, 99411, 99412, 99413, 99414, 99418, 99197, 99198, 99199, 99200, 99206, 99603, 99559, 99560, 99561, 99602}
    gTierCheck.Warrior.S2.t16 = {99047, 99046, 99036, 99035, 99034, 99411, 99412, 99413, 99414, 99418, 99197, 99198, 99199, 99200, 99206, 99603, 99559, 99560, 99561, 99602}
    gTierCheck.Warrior.S3.t16 = {}

    gTierCheck.Paladin = {}
    gTierCheck.Paladin.S1 = {}
    gTierCheck.Paladin.S2 = {}
    gTierCheck.Paladin.S3 = {}
    gTierCheck.Paladin.S1.t15 = {}
    gTierCheck.Paladin.S2.t15 = {}
    gTierCheck.Paladin.S3.t15 = {}
    gTierCheck.Paladin.S1.t16 = {}
    gTierCheck.Paladin.S2.t16 = {}
    gTierCheck.Paladin.S3.t16 = {}

    gTierCheck.Hunter = {}
    gTierCheck.Hunter.S1 = {}
    gTierCheck.Hunter.S2 = {}
    gTierCheck.Hunter.S3 = {}
    gTierCheck.Hunter.S1.t15 = {}
    gTierCheck.Hunter.S2.t15 = {}
    gTierCheck.Hunter.S3.t15 = {}
    gTierCheck.Hunter.S1.t16 = {}
    gTierCheck.Hunter.S2.t16 = {}
    gTierCheck.Hunter.S3.t16 = {}

    gTierCheck.Rogue = {}
    gTierCheck.Rogue.S1 = {}
    gTierCheck.Rogue.S2 = {}
    gTierCheck.Rogue.S3 = {}
    gTierCheck.Rogue.S1.t15 = {}
    gTierCheck.Rogue.S2.t15 = {}
    gTierCheck.Rogue.S3.t15 = {}
    gTierCheck.Rogue.S1.t16 = {}
    gTierCheck.Rogue.S2.t16 = {}
    gTierCheck.Rogue.S3.t16 = {}

    gTierCheck.Priest = {}
    gTierCheck.Priest.S1 = {}
    gTierCheck.Priest.S2 = {}
    gTierCheck.Priest.S3 = {}
    gTierCheck.Priest.S1.t15 = {}
    gTierCheck.Priest.S2.t15 = {}
    gTierCheck.Priest.S3.t15 = {}
    gTierCheck.Priest.S1.t16 = {}
    gTierCheck.Priest.S2.t16 = {}
    gTierCheck.Priest.S3.t16 = {}

    gTierCheck["Death Knight"] = {}
    gTierCheck["Death Knight"]["S1"] = {}
    gTierCheck["Death Knight"]["S2"] = {}
    gTierCheck["Death Knight"]["S3"] = {}
    gTierCheck["Death Knight"]["S1"]["t15"] = {}
    gTierCheck["Death Knight"]["S2"]["t15"] = {}
    gTierCheck["Death Knight"]["S3"]["t15"] = {}
    gTierCheck["Death Knight"]["S1"]["t16"] = {}
    gTierCheck["Death Knight"]["S2"]["t16"] = {}
    gTierCheck["Death Knight"]["S3"]["t16"] = {}

    gTierCheck.Shaman = {}
    gTierCheck.Shaman.S1 = {}
    gTierCheck.Shaman.S2 = {}
    gTierCheck.Shaman.S3 = {}
    gTierCheck.Shaman.S1.t15 = {}
    gTierCheck.Shaman.S2.t15 = {}
    gTierCheck.Shaman.S3.t15 = {}
    gTierCheck.Shaman.S1.t16 = {}
    gTierCheck.Shaman.S2.t16 = {}
    gTierCheck.Shaman.S3.t16 = {}

    gTierCheck.Mage = {}
    gTierCheck.Mage.S1 = {}
    gTierCheck.Mage.S2 = {}
    gTierCheck.Mage.S3 = {}
    gTierCheck.Mage.S1.t15 = {}
    gTierCheck.Mage.S2.t15 = {}
    gTierCheck.Mage.S3.t15 = {}
    gTierCheck.Mage.S1.t16 = {99078, 99079, 99077, 99083, 99084, 99658, 99659, 99575, 99576, 99657, 99152, 99153, 99160, 99161, 99162, 99397, 99398, 99399, 99400, 99401}
    gTierCheck.Mage.S2.t16 = {99078, 99079, 99077, 99083, 99084, 99658, 99659, 99575, 99576, 99657, 99152, 99153, 99160, 99161, 99162, 99397, 99398, 99399, 99400, 99401}
    gTierCheck.Mage.S3.t16 = {99078, 99079, 99077, 99083, 99084, 99658, 99659, 99575, 99576, 99657, 99152, 99153, 99160, 99161, 99162, 99397, 99398, 99399, 99400, 99401}

    gTierCheck.Warlock = {}
    gTierCheck.Warlock.S1 = {}
    gTierCheck.Warlock.S2 = {}
    gTierCheck.Warlock.S3 = {}
    gTierCheck.Warlock.S1.t15 = {}
    gTierCheck.Warlock.S2.t15 = {}
    gTierCheck.Warlock.S3.t15 = {}
    gTierCheck.Warlock.S1.t16 = {}
    gTierCheck.Warlock.S2.t16 = {}
    gTierCheck.Warlock.S3.t16 = {}

    gTierCheck.Monk = {}
    gTierCheck.Monk.S1 = {}
    gTierCheck.Monk.S2 = {}
    gTierCheck.Monk.S3 = {}
    gTierCheck.Monk.S1.t15 = {}
    gTierCheck.Monk.S2.t15 = {}
    gTierCheck.Monk.S3.t15 = {}
    gTierCheck.Monk.S1.t16 = {}
    gTierCheck.Monk.S2.t16 = {}
    gTierCheck.Monk.S3.t16 = {}

    gTierCheck.Druid = {}
    gTierCheck.Druid.S1 = {}
    gTierCheck.Druid.S2 = {}
    gTierCheck.Druid.S3 = {}
    gTierCheck.Druid.S4 = {}
    gTierCheck.Druid.S1.t15 = {}
    gTierCheck.Druid.S2.t15 = {}
    gTierCheck.Druid.S3.t15 = {}
    gTierCheck.Druid.S4.t15 = {}
    gTierCheck.Druid.S1.t16 = {}
    gTierCheck.Druid.S2.t16 = {}
    gTierCheck.Druid.S3.t16 = {}
    gTierCheck.Druid.S4.t16 = {}

local gTrinketCheck = {}
    gTrinketCheck.Intellect = {}
    gTrinketCheck.Intellect.Proc = {105572, 105540, 105422, 104576, 104544, 104426, 105323, 105291, 105173, 102300, 102293, 102303, 104675, 104825, 104793, 104924, 105042, 105074, 96888, 96827, 96144, 96083, 94531, 94521, 95772, 95711}
    gTrinketCheck.Intellect.Stacking = {105648, 104652, 105399, 102310, 104901, 105150, 96041, 94513, 95669}
    gTrinketCheck.Agility = {}
    gTrinketCheck.Strength = {}
-- Tables for Tier Bonus and Trinkets

function GInventory(tier, version)

  if tier == "Tier" then

    local tierslots = {1, 3, 5, 7, 10}
    local class = ccrPlayerClass()
    local spec = ccrUnitSpec("player")
    local tierid = gTierCheck[""..class..""]["S"..""..spec..""][""..version..""]
    local SetNumber = 0
    local headid = GetInventoryItemID("player", 1)
    local shoulderid = GetInventoryItemID("player", 3)
    local chestid = GetInventoryItemID("player", 5)
    local legsid = GetInventoryItemID("player", 7)
    local handsid = GetInventoryItemID("player", 10)
    
    for i, v in pairs(tierid) do
      if headid == v then SetNumber = SetNumber+1 break end
    end
    for i, v in pairs(tierid) do
      if shoudlerid == v then SetNumber = SetNumber+1 break end
    end
    for i, v in pairs(tierid) do
      if chestid == v then SetNumber = SetNumber+1 break end
    end
    for i, v in pairs(tierid) do
      if legsid == v then SetNumber = SetNumber+1 break end
    end
    for i, v in pairs(tierid) do
      if handsid == v then SetNumber = SetNumber+1 break end
    end

    return SetNumber
  end

  if tier == "Trinkets" then
    local trinketslots = {13, 14}
    local class = ccrPlayerClass()
    local spec = ccrUnitSpec("player")

    if class == "Mage" or class == "Warlock" or (class == "Shaman" and spec == 1) or (class == "priest" and spec == 3) or (class == "druid" and spec == 1) then
    end
  end
end

function TierBonusChecker()
  
  local tierslots = {1, 3, 5, 7, 10}
  
  local tierid = {}
  tierid.head = {99084, 99576, 99161, 99398}
  tierid.shoulder = {99079, 99659, 99153, 99401}
  tierid.chest = {99078, 99658, 99152, 99400}
  tierid.legs = {99077, 99657, 99162, 99399}
  tierid.hands = {99083, 99575, 99160, 99397}
  
  local SetNumber = 0
  
  local headid = GetInventoryItemID("player", 1)
  local shoulderid = GetInventoryItemID("player", 3)
  local chestid = GetInventoryItemID("player", 5)
  local legsid = GetInventoryItemID("player", 7)
  local handsid = GetInventoryItemID("player", 10)
  
  for i, v in pairs(tierid.head) do
    if headid == v then SetNumber = SetNumber+1 break end
  end
  for i, v in pairs(tierid.shoulder) do
    if shoudlerid == v then SetNumber = SetNumber+1 break end
  end
  for i, v in pairs(tierid.chest) do
    if chestid == v then SetNumber = SetNumber+1 break end
  end
  for i, v in pairs(tierid.legs) do
    if legsid == v then SetNumber = SetNumber+1 break end
  end
  for i, v in pairs(tierid.hands) do
    if handsid == v then SetNumber = SetNumber+1 break end
  end

  return SetNumber
end

-- ripped from CommanderSirow of the wowace forums
function G1zStarttd()
  if not dummyttd then dummyttd = true else dummyttd = false end
   -- Setup trigger (once)
   if not WA_TTD_Windows then
      -- User variables
      WA_TTD_Windows = 8             -- Max number of samples
      WA_TTD_Steps = 1.5             -- Time between samples
      
      -- Code variables
      WA_TTD_GUID = nil              -- Remember GUID of mob you are tracking
      WA_TTD_MaxValue = 0            -- Remember max HP for relative shift
      WA_TTD_Last = GetTime()        -- Remember last update
      WA_TTD_Start = nil             -- First data collection time for relative shift
      WA_TTD_Index = 0               -- Current ring buffer index
      WA_TTD_Times = {}              -- Ring buffer data - data_x
      WA_TTD_Values = {}             -- Ring buffer data - data_y
      WA_TTD_Samples = 0             -- Number of collected (active) samples
      WA_TTD_Estimate = nil          -- Estimated end time (not relative)
   end
   
   -- Query current time (throttle updating over time)
   local now = GetTime()
   if now - WA_TTD_Last >= WA_TTD_Steps then
      -- Current data
      local data = UnitHealth("target")
      
      -- Reset data?
      if data == UnitHealthMax("target") or not WA_TTD_GUID or WA_TTD_GUID ~= UnitGUID("target") then
         WA_TTD_GUID = nil
         WA_TTD_Start = nil
         WA_TTD_Estimate = nil
      end
      
      -- No start time?
      if not WA_TTD_Start or not WA_TTD_GUID then
         WA_TTD_Start = now
         WA_TTD_Index = 0
         WA_TTD_Samples = 0
         WA_TTD_MaxValue = UnitHealthMax("target") / 2
         WA_TTD_GUID = UnitGUID("target")
      end
      
      -- Remember current time
      WA_TTD_Last = now
      
      -- Save new data (Use relative values to prevent "overflow")
      WA_TTD_Values[WA_TTD_Index] = data - WA_TTD_MaxValue
      WA_TTD_Times[WA_TTD_Index] = now - WA_TTD_Start
      
      -- Next index
      WA_TTD_Index = WA_TTD_Index + 1
      
      -- Update number of active samples
      if WA_TTD_Index > WA_TTD_Samples then
         WA_TTD_Samples = WA_TTD_Index
      end
      
      -- Using table as ring buffer        
      if WA_TTD_Index >= WA_TTD_Windows then
         WA_TTD_Index = 0
      end
      
      -- Min number of samples
      if WA_TTD_Samples >= 2 then
         -- Estimation variables
         local SS_xy, SS_xx, x_M, y_M = 0, 0, 0, 0
         
         -- Calc pre-solution values
         for index = 0, WA_TTD_Samples-1 do
            -- Calc mean value 
            x_M = x_M + WA_TTD_Times[index] / WA_TTD_Samples
            y_M = y_M + WA_TTD_Values[index] / WA_TTD_Samples
            
            -- Calc sum of squares
            SS_xx = SS_xx + WA_TTD_Times[index] * WA_TTD_Times[index]
            SS_xy = SS_xy + WA_TTD_Times[index] * WA_TTD_Values[index]
         end
         
         -- Few last additions to mean value / sum of squares
         SS_xx = SS_xx - WA_TTD_Samples * x_M * x_M
         SS_xy = SS_xy - WA_TTD_Samples * x_M * y_M
         
         -- Results
         local a_0, a_1, x = 0, 0, 0
         
         -- Calc a_0, a_1 of linear interpolation (data_y = a_1 * data_x + a_0)
         a_1 = SS_xy / SS_xx
         a_0 = y_M - a_1 * x_M
         
         -- Find zero-point (Switch back to absolute values)
         a_0 = a_0 + WA_TTD_MaxValue
         x = - (a_0 / a_1)
         
         -- Valid/Usable solution
         if a_1 and a_1 < 1 and a_0 and a_0 > 0 and x and x > 0 then
            WA_TTD_Estimate = x + WA_TTD_Start
            -- Fallback 
         else
            WA_TTD_Estimate = nil
         end
         
         -- Not enough data
      else
         WA_TTD_Estimate = nil
      end
   end
   
   -- Training Dummy
   if UnitName("target") == "Raider's Training Dummy" then
      if not dummyttd then return 4 else return 200 end
   end
   -- Training Dummy
   
   -- No/false information
   if not WA_TTD_Estimate then
      return "<No Information>"
      
      -- Already over
   elseif now > WA_TTD_Estimate then 
      return "<Estimated to be dead>"
      
      -- Seconds only
   else--[[if WA_TTD_Estimate - now <= 60 then--]]
      return string.format("%0.2d", WA_TTD_Estimate - now)
      
      -- More than seconds
      --[[else
      return string.format("%d:%0.2d", (WA_TTD_Estimate - now) / 60, (WA_TTD_Estimate - now) % 60)--]]
   end
end

function expTTD(unit)

  -- Setup trigger (once)
    if not nMaxSamples then
      -- User variables
      nMaxSamples = 15             -- Max number of samples
      nScanThrottle = 0.5             -- Time between samples
      
      -- Code variables
      --WA_TTD_GUID = nil              -- Remember GUID of mob you are tracking
      --WA_TTD_MaxValue = 0            -- Remember max HP for relative shift
      -- nLastScan = GetTime()        -- Remember last update
      --WA_TTD_Start = nil             -- First data collection time for relative shift
      --WA_TTD_Index = 0               -- Current ring buffer index
      --WA_TTD_Times = {}              -- Ring buffer data - data_x
      --WA_TTD_Values = {}             -- Ring buffer data - data_y
      --WA_TTD_Samples = 0             -- Number of collected (active) samples
      --WA_TTD_Estimate = nil          -- Estimated end time (not relative)
    end

  -- Training Dummy alternate between 4 and 200 for cooldowns
    if tContains(Dummies, IGetName(unit)) then if not dummyttd then TTD[unit] = 4 return else TTD[unit] = 200 return end end
    --
  
  -- if health = 0 then set time to death to negative
  if GHealth(unit) == 0 then TTD[unit] = -1 return end

  -- Query current time (throttle updating over time)
    local nTime = GetTime()
    if not TTDM[unit] or nTime - TTDM[unit].nLastScan >= nScanThrottle then
      -- Current data
      local data = GHealth(unit)
      
      -- Reset data?
      -- if data == UnitHealthMax("target") or not WA_TTD_GUID or WA_TTD_GUID ~= UnitGUID("target") then -- disalbe
      --   WA_TTD_Estimate = nil -- disalbe
      --   WA_TTD_Start = nil -- disalbe
      --   WA_TTD_GUID = nil -- disalbe
      -- end -- disalbe
      
      -- No start time?
      -- if not WA_TTD_Start or not WA_TTD_GUID then
      --   WA_TTD_Start = nTime
      --   WA_TTD_Index = 0
      --   WA_TTD_Samples = 0
      --   WA_TTD_MaxValue = UnitHealthMax("target") / 2
      --   WA_TTD_GUID = UnitGUID("target")
      -- end
      if not TTDM[unit] then
        TTDM[unit] = {start = nTime, index = 1, maxvalue = GHealth(unit, max)/2, values = {}, nLastScan = nTime, estimate = nil}
      end
      
      -- Remember current time
      TTDM[unit].nLastScan = nTime
      
      if TTDM[unit].index > nMaxSamples then
        TTDM[unit].index = 1
      end
      -- Save new data (Use relative values to prevent "overflow")
      -- WA_TTD_Values[WA_TTD_Index] = data - WA_TTD_MaxValue
      -- WA_TTD_Times[WA_TTD_Index] = nTime - WA_TTD_Start
      TTDM[unit].values[TTDM[unit].index] = {dmg = data - TTDM[unit].maxvalue, time = nTime - TTDM[unit].start}

      -- Next index
      -- WA_TTD_Index = WA_TTD_Index + 1
      -- TTDM[unit].index = TTDM[unit].index + 1 -- enable
      
      -- Update number of active samples
      -- if WA_TTD_Index > WA_TTD_Samples then
      --   WA_TTD_Samples = WA_TTD_Index
      -- end
      -- if TTDM[unit].index > TTDM[unit].samples--[[+1--]] then TTDM[unit].samples = TTDM[unit].index end
      
      -- Using table as ring buffer        
      -- if WA_TTD_Index >= nMaxSamples then
      --   WA_TTD_Index = 0
      -- end
      
      if #TTDM[unit].values >= 2 then
        -- Estimation variables
        local SS_xy, SS_xx, x_M, y_M = 0, 0, 0, 0

        -- Calc pre-solution values
        for i = --[[0--]]1, #TTDM[unit].values do
          -- Calc mean value
          x_M = x_M + TTDM[unit].values[i].time / #TTDM[unit].values
          y_M = y_M + TTDM[unit].values[i].dmg / #TTDM[unit].values

          -- Calc sum of squares
          SS_xx = SS_xx + TTDM[unit].values[i].time * TTDM[unit].values[i].time
          SS_xy = SS_xy + TTDM[unit].values[i].time * TTDM[unit].values[i].dmg
        end

        -- Few last addition to mean value / sum of squares
        SS_xx = SS_xx - #TTDM[unit].values * x_M * x_M
        SS_xy = SS_xy - #TTDM[unit].values * x_M * y_M

        -- Results
        local a_0, a_1, x = 0, 0, 0

        -- Calc a_0, a_1 of linear interpolation (data_y = a_1 * data_x + a_0)
        a_1 = SS_xy / SS_xx
        a_0 = y_M - a_1 * x_M

        -- Find zero-point (Switch back to absolute values)
        a_0 = a_0 + TTDM[unit].maxvalue
        x = - (a_0 / a_1)

        -- Valid/Usable solution
        if a_1 and a_1 < 1 and a_0 and a_0 > 0 and x and x > 0 then
          TTDM[unit].estimate = x + TTDM[unit].start
          -- Fallback
        else
          TTDM[unit].estimate = nil
        end

        -- Not enough data
      else
        TTDM[unit].estimate = nil
      end      
      TTDM[unit].index = TTDM[unit].index + 1 -- enable
    end
    --    
  -- No/false information
  -- if not WA_TTD_Estimate then
    -- return math.huge
    --
  -- Already over
  -- elseif nTime > WA_TTD_Estimate then 
    -- return -1
    --
  -- Seconds only
  -- elseif WA_TTD_Estimate - nTime <= 60 then -- disable
  --   return string.format("%0.2d", WA_TTD_Estimate - nTime) -- disable
    --  
  -- More than seconds
  -- else -- disable
  --   return string.format("%d:%0.2d", (WA_TTD_Estimate - nTime) / 60, (WA_TTD_Estimate - nTime) % 60) -- disable
  -- else
  --   return WA_TTD_Estimate
  -- end

  if not TTDM[unit].estimate then
    TTD[unit] = math.huge
  elseif nTime > TTDM[unit].estimate then
    TTD[unit] = -1
  else
    TTD[unit] = TTDM[unit].estimate-nTime
  end
end

-- ripped from CommanderSirow of the wowace forums

function ggalakrasrate()

  if not gitemframe then
    gitemframe = CreateFrame("GameTooltip", "gitemframe", UIParent, "GameTooltipTemplate")
    gitemframe:SetOwner(UIParent, "ANCHOR_NONE")
  end

  if not IsEquippedItem("Evil Eye of Galakras") then return 1 end

  if GetItemInfo(GetInventoryItemLink("player", 13)) == "Evil Eye of Galakras" then
    gitemframe:ClearLines()
    gitemframe:SetHyperlink(GetInventoryItemLink("player", 13))

    local text = gitemframeTextLeft8:GetText()
    local ratep = string.match(text, "%d.+%%")
    local rate = string.gsub(ratep, "%%", "")
    return 1+tonumber(rate)/100
  else
    gitemframe:ClearLines()
    gitemframe:SetHyperlink(GetInventoryItemLink("player", 14))

    local text = gitemframeTextLeft8:GetText()
    local ratep = string.match(text, "%d.+%%")
    local rate = string.gsub(ratep, "%%", "")
    return 1+tonumber(rate)/100
  end
end

function pullallunitsm(spell, range)
  if _pullMThrottle == nil then _pullMThrottle = 0 end
  if _pullMThrottle > GetTime() then return end
  _pullMThrottle = GetTime()+.5
  spelltable = string.gsub(spell, "%s", "")
  _G["tNoObject"..spelltable] = {}
  _G["t"..spelltable] = {}

  for i = 1, #Targets do

    if IExists(Targets[i]) then

      ISetAsUnitID(Targets[i], "Internal")
      local curobj = Targets[i]
      
      if (UnitIsTappedByPlayer("Internal") or tContains(Dummies, IGetName(Targets[i]))) and
      not GAura(curobj, "Misery, Sorrow, and Gloom") and not GAura(curobj, "Mark of Anguish") and not GAura(curobj, "Dark Meditation")
      and not GAura(curobj, "Touch of Y'Shaarj") and not GAura(curobj, "Empowered Touch of Y'Shaarj")
      and (not range or range >= GDistance(curobj)+GCombatReach(curobj)) then
        local name = GAura(curobj, spell, "", "PLAYER")
        if name == spell then table.insert(_G["t"..spelltable], curobj) end
        if name ~= spell and GDistance(curobj) <= 40 and ICanAttack(Player.GUID, curobj) and GLOS(curobj) then table.insert(_G["tNoObject"..spelltable], curobj) end
      end
    end
  end
end

function GTargetListControl()
  if ccRS.UseAnkhyorG1zStar ~= 3 then -- ccR

    -- turn on ccR
    if GObjectList ~= "ccR" then GObjectList = "ccR" end
    -- turn on ccR

    -- turn off GStar
      if ThrottleFrame then
        ThrottleFrame:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
        ThrottleFrame:UnregisterEvent("PLAYER_DEAD")
      end
    for i = 1, #TargetsPreliminary do
      table.remove(TargetsPreliminary, i)
    end
    for i = 1, #Targets do
      table.remove(Targets, i)
    end
    -- turn off GStar

    return
  end

  if ccRS.UseAnkhyorG1zStar == 3 then -- GStar


    -- turn on GStar
      if GObjectList ~= "GStar" then GObjectList = "GStar" end
      if ThrottleFrame then
        ThrottleFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
        ThrottleFrame:RegisterEvent("PLAYER_DEAD")
      end
    -- turn on GStar

    -- turn off ccR
    for i = #ccrObjectListTable, 1, -1 do
      table.remove(ccrObjectListTable, i)
    end
    for i = #tblPGetNearbyEnemies, 1, -1 do
      table.remove(tblPGetNearbyEnemies, i)
    end
    for i = #tblPGetMeleeEnemies, 1, -1 do
      table.remove(tblPGetMeleeEnemies, i)
    end
    for i = #tblTGetNearbyEnemies, 1, -1 do
      table.remove(tblTGetNearbyEnemies, i)
    end
    for i = #tblNearbyPlayers, 1, -1 do
      table.remove(tblNearbyPlayers, i)
    end
    for i = #tblGroupedNPCHealth, 1, -1 do
      table.remove(tblGroupedNPCHealth, i)
    end
    for i = #tblGroupedPlayersHealth, 1, -1 do
      table.remove(tblGroupedPlayersHealth, i)
    end
    -- turn off ccR

    GTargetList() -- run my target list collection
  end
end

  local Ignore = {}
  Ignore.Name = {
    "Manifestation",
    "Kor'Kron Cannon",
    "Spike Mine"
  }
  Ignore.Type = {
    "Critter",
    "Critter nil",
    "Wild Pet",
    "Pet",
    "Totem"
  }

function GTargetList()
  -- local start = debugprofilestop()

  if UnitIsDeadOrGhost("player") then return end
  
  if tLastTargetList == nil or GetTime() - tLastTargetList > 0.5 then
    -- TargetsPreliminary = {}
    for i = #TargetsPreliminary, 1, -1 do
      table.remove(TargetsPreliminary, i)
    end
    for i = 1, GetTotalObjects(3) do table.insert(TargetsPreliminary, GetObjectListEntry(i).GUID) end
    tLastTargetList = GetTime()
  elseif tLastTargetMaint == nil or GetTime() - tLastTargetMaint > 0.15 then

    for i = 1, #TargetsPreliminary do -- add filtered
      if IExists(TargetsPreliminary[i])
      and GHealth(TargetsPreliminary[i]) > 0
      and not tContains(Targets, TargetsPreliminary[i])
      and not tContains(Ignore.Name, IGetName(TargetsPreliminary[i]))
      and not tContains(Ignore.Type, GCreatureType(TargetsPreliminary[i]))
      and ICanAttack(Player.GUID, TargetsPreliminary[i])
      then
        table.insert(Targets, TargetsPreliminary[i])
      end
    end

    for i = 1, #Targets do -- check what needs to be removed
      if not IExists(Targets[i]) or (GHealth(Targets[i]) == 0 or not ICanAttack(Player.GUID, Targets[i]))
      then
        _G["remove"..i] = true
      end
    end

    for i = #Targets, 1, -1 do -- remove what needs to be removed
      if _G["remove"..i] then
        table.remove(Targets, i)
        _G["remove"..i] = false
      end
    end

    tLastTargetMaint = GetTime()

    if ccRS.Auto_Loot
    and (GetTime()-ccR_Last_AutoLoot_Scanned) > 1.5
    and not ccrPlayerIsCastingOrChanneling()
    and GetNumLootItems() == 0
    and not ccrPIIC()
    then
      for i = 1, #TargetsPreliminary do
        local obj = TargetsPreliminary[i]
        if obj
        and IExists(obj)
        and GDistance(obj) <= max(5, (13 / 6) + GCombatReach(obj))
        and not bPauseAutoLoot
        then
          if IIsLootable(obj) then
            IObjectInteract(obj)
          end
          if IIsSkinnable(obj) then
            IObjectInteract(obj)    
          end
        end
      end
     ccR_Last_AutoLoot_Scanned = GetTime()
    end
  end

  -- for k, v in pairs(TTD) do
  --   if not tContains(Targets, k) then table.remove(TTD, k) end
  -- end

  dummyttd = not dummyttd

  for i = 1, #Targets do
    if IExists(Targets[i]) then
      ISetAsUnitID(Targets[i], "Internal")
      if UnitIsTappedByPlayer("Internal") or tContains(Dummies, IGetName(Targets[i])) then expTTD(Targets[i]) end
    end
  end
  -- ChatFrame5:AddMessage(""..debugprofilestop()-start.."")
end

HealersPreliminary = {}

function HealerList()
  -- local start = debugprofilestop()
  
  if UnitIsDeadOrGhost("player") then return end

  -- if tLastHealerList == nil or GetTime() - tLastHealerList > 0.5 then
    for i = #HealersPreliminary, 1, -1 do
      table.remove(HealersPreliminary, i)
    end
    if GetNumGroupMembers() > 0 then
    end
    -- for i = 1, GetTotalObjects(4) do table.insert(HealersPreliminary, GetObjectListEntry(i).GUID) end
    -- tLastHealerList = GetTime()
  -- elseif tLastHealerMaint == nil or GetTime() - tLastHealerMaint > 0.15 then

  -- end
end

-- functions that do something
  function GPet(unit, distance)
     if unit:GetDistance(Pet) <= distance+unit:GetCombatReach() then
        return true
     else
        return false
     end
  end

function GPlayerCount(yards)
  
  local GMobCount
  
  if tGPlayerCount == nil or (GetTime()-tGPlayerCount) > 0.25 then
    
    GMobCount = 0
    
    for i = 1, #Targets do
      if IExists(Targets[i]) and GDistance(Targets[i]) <= yards+GCombatReach(Targets[i]) then GMobCount = GMobCount + 1 end
    end
    
    tGPlayerCount = GetTime()
    nGPlayerCount = GMobCount
    
    if GMobCount ~= nil then return GMobCount end
  else
    
    if nGPlayerCount ~= nil then return nGPlayerCount end
  end

    return 0 -- CCR GUID
end

function GTargetCount(yards)

  if not Target or Target:GetHealth() == 0 then return 0 end

  local GMobCount

  if tGTargetCount == nil or (GetTime()-tGTargetCount) > 0.25 then

    GMobCount = 0

    for i = 1, #Targets do
      if IExists(Targets[i]) and GDistance(Targets[i], Target.GUID) <= yards+GCombatReach(Targets[i]) then GMobCount = GMobCount + 1 end
    end

    tGTargetCount = GetTime()
    nGTargetCount = GMobCount
        
    if GMobCount ~= nil then
      if GMobCount == 0 then return 1 end
      return GMobCount
    end
    else
      
    if nGTargetCount ~= nil then
      if nGTargetCount == 0 then return 1 end
      return nGTargetCount
    end
  end

    return 1 -- CCR GUID
end

  function GFace(guid) -- FH GUID
  FaceLocation(IGetLocation(guid))
end

function GFacing(guid, other)
  local X, Y, Z, R = IGetLocation(guid)
  local OtherX, OtherY = IGetLocation(other)

    return ((X - OtherX) * math.cos(-R)) - ((Y - OtherY) * math.sin(-R)) < 0; -- FH GUID
end

  function GCast(guid, Name, ...)
    -- if Name == nil then
    --   error("Usage: GCast(GUID, Name)")
    --   return
    -- end
  if type(Name) == "number" then Name = SpellIDToName(Name) end

  ISetAsUnitID(guid, "Internal")
  CastSpellByName(Name, "Internal")

  if AreaSpellIsPending() == true then
      if ... then
        local X, Y, Z = ...
    CastAtLocation(X + math.random(-0.01, 0.01), Y + math.random(-0.01, 0.01), Z + math.random(-0.01, 0.01))
  end
      local X, Y, Z = IGetLocation(guid)
      CastAtLocation(X + math.random(-0.01, 0.01), Y + math.random(-0.01, 0.01), Z + math.random(-0.01, 0.01))
    end -- FH GUID
end

function GLOS(guid, other, increase)
  other = other or Player.GUID
  local X1, Y1, Z1 = IGetLocation(guid)
  local X2, Y2, Z2 = IGetLocation(other)
    return not TraceLine(X1, Y1, Z1 + (Increase or 2), X2, Y2, Z2 + (Increase or 2), 0x10); -- FH GUID
  end

  function GHealth(guid, max)
    local Type = IGetType(guid)

    if Type ~= 3 and Type ~= 4 then
      error("Invalid type of object.")
      return nil
    end

    ISetAsUnitID(guid, "Internal")
    if max then return UnitHealthMax("Internal")
    else
      return UnitHealth("Internal") -- FH GUID
    end
  end

  function GCreatureType(guid)

    ISetAsUnitID(guid, "Internal")
    return UnitCreatureType("Internal") -- FH GUID
  end

  function GDistance(target, base) -- FH GUID
    if base == nil then
      base = Player.GUID
    end

    local X1, Y1, Z1 = IGetLocation(target)
    local X2, Y2, Z2 = IGetLocation(base)

    return math.sqrt(((X2 - X1) ^ 2) + ((Y2 - Y1) ^ 2) + ((Z2 - Z1) ^ 2))
  end

  function GAura(guid, ...)
    local Type = IGetType(guid)

    if Type ~= 3 and Type ~= 4 then
      error("Invalid type of object.")
      return nil
end

    ISetAsUnitID(guid, "Internal")

    if UnitBuff("Internal", ...) then return UnitBuff("Internal", ...) elseif UnitDebuff("Internal", ...) then return UnitDebuff("Internal", ...) else return UnitAura("Internal", ...) end -- FH GUID
  end

  function GCombatReach(guid)
    local Type = IGetType(guid)

    if Type ~= 3 and Type ~= 4 then
      error("Invalid type of object.")
      return nil
    end
    
    return IGetFloatDescriptor(guid, 0x110)   -- FH GUID
  end

  function GPullEnemies(reach, tapped) -- gets enemies in an AoE
   if #Targets == 0 then return {} end
   local units = {}
   for i = 1, #Targets do
    if tapped then ISetAsUnitID(Targets[i], "Internal") end
    if GDistance(Targets[i]) <= reach and (not tapped or UnitIsTappedByPlayer("Internal")) then
       table.insert(units, Targets[i])
    end
   end
   return units
  end

  function GSmartAoE(reach, size, tapped) -- smart aoe placement credits to phelps a.k.a doc|brown
    local units = GPullEnemies(reach, tapped)
    local win = 0
    local winners = {}
    for _, enemy in ipairs(units) do
      local neighbors = 0
      for _, neighbor in ipairs(units) do
        if GDistance(enemy, neighbor) <= size then
          neighbors = neighbors + 1
        end
      end
      if neighbors >= win and neighbors > 0 then
        table.insert(winners, enemy)
        win = neighbors
      end
    end
    return GAvgPosObjects(winners)
  end -- use it like this: GCast(Player.GUID, 104232, GSmartAoE(35, 8))
  -- The Player.GUID part is needed because I can't be bothered to code properly

  function GAvgPosObjects (Targets) -- FH GUID
    local Total = #Targets;
    local X, Y, Z = 0, 0, 0;

    for Key, ThisObject in pairs(Targets) do
      if ThisObject then
        local ThisX, ThisY, ThisZ = IGetLocation(ThisObject);
        if ThisX and ThisY then
          X = X + ThisX;
          Y = Y + ThisY;
          Z = Z + ThisZ;
        end
      end
    end

    X = X / Total;
    Y = Y / Total;
    Z = Z / Total;
    return X, Y, Z;
  end

  function GSelect(a)
    if a == "health" then
      local max, maxhp = nil, 0
      for i = 1, #Targets do
        ISetAsUnitID(Targets[i], "Internal")
        if GHealth(Targets[i]) > maxhp and (UnitIsTappedByPlayer("Internal") or tContains(Dummies, IGetName(Targets[i]))) and Targets[i] ~= Target.GUID then max = Targets[i] end
      end
      return max
    end
  end
-- functions that do something

-- legacy
  -- function stung1zstar()
    --   if isStun then
    --     isStun = false
    --     print("turning off stun.")
    --   else
    --     isStun = true
    --     print("turning on stun.")
    --   end
  -- end

  -- function AoEToggle()
    --   if not AoEFrame then
    --     AoEFrame = CreateFrame("Frame", "AoEFrame", UIParent)
    --     AoEFrame:SetFrameStrata("DIALOG")
    --     AoEFrame:SetWidth("64")
    --     AoEFrame:SetHeight("64")
    --     isAoE_One = AoEFrame:CreateTexture("isAoE_One")
    --     isAoE_One:SetTexture("Interface\\Addons\\_ccR\\sys\\1.tga")
    --     isAoE_One:SetTexCoord(0,1,0,1)
    --     isAoE_One:SetAllPoints(AoEFrame)
    --     isAoE_Two = AoEFrame:CreateTexture("isAoE_Two")
    --     isAoE_Two:SetTexture("Interface\\Addons\\_ccR\\sys\\2.tga")
    --     isAoE_Two:SetTexCoord(0,1,0,1)
    --     isAoE_Two:SetAllPoints(AoEFrame)
    --     isAoE_Three = AoEFrame:CreateTexture("isAoE_Three")
    --     isAoE_Three:SetTexture("Interface\\Addons\\_ccR\\sys\\3.tga")
    --     isAoE_Three:SetTexCoord(0,1,0,1)
    --     isAoE_Three:SetAllPoints(AoEFrame)
    --     AoEFrame:SetPoint("CENTER")
    --     AoEFrame:SetMovable()
    --     AoEFrame:EnableMouse(true)
    --     AoEFrame:RegisterForDrag("LeftButton")
    --     AoEFrame:SetScript("OnDragStart", AoEFrame.StartMoving)
    --     AoEFrame:SetScript("OnDragStop", AoEFrame.StopMovingOrSizing)
    --   end
    --   if isAoE == nil then
    --     isAoE = 0
    --     isAoE_One:Show()
    --     isAoE_Two:Hide()
    --     isAoE_Three:Hide()
    --     return
    --   end
    --   if isAoE == 0 then
    --     isAoE = 1
    --     isAoE_One:Hide()
    --     isAoE_Two:Show()
    --     print("cleave on")
    --   elseif isAoE == 1 then
    --     isAoE = 2
    --     isAoE_Two:Hide()
    --     isAoE_Three:Show()
    --     print("AoE on")
    --   elseif isAoE == 2 then
    --     isAoE = 0
    --     isAoE_Three:Hide()
    --     isAoE_One:Show()
    --     print("single target on")
    --   end
    -- end
-- legacy